{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Edit a FITS header\n",
    "\n",
    "## Authors\n",
    "Adrian Price-Whelan, Adam Ginsburg, Stephanie T. Douglas, Kelle Cruz\n",
    "\n",
    "## Learning Goals\n",
    "* Read a FITS file \n",
    "* Retrieve FITS header metadata\n",
    "* Edit the FITS header \n",
    "* Write the modified file as a FITS file\n",
    "\n",
    "## Keywords\n",
    "FITS, file input/output\n",
    "\n",
    "## Summary\n",
    "This tutorial describes how to read in and edit a FITS header, and then write \n",
    "it back out to disk. For this example we're going to change the `OBJECT` \n",
    "keyword."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from astropy.io import fits"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``astropy.io.fits`` provides a lot of flexibility for reading FITS \n",
    "files and headers, but most of the time the convenience functions are\n",
    "the easiest way to access the data. ``fits.getdata()`` reads only the \n",
    "data from a FITS file, but with the `header=True` keyword argument will\n",
    "also read the header. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data, header = fits.getdata(\"input_file.fits\", header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is also a dedicated function for reading only the \n",
    "header:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "hdu_number = 0 # HDU means header data unit\n",
    "fits.getheader('input_file.fits', hdu_number)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But `getdata()` can get both the data and the header, so it's a useful \n",
    "command to remember. Since the primary HDU of a FITS file must contain image data, \n",
    "the data is now stored in a ``numpy`` array. The header is stored in an \n",
    "object that acts like a standard Python dictionary. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# But hdu_number = 0 is the PRIMARY HDU.How many HDUs are in this file?\n",
    "fits_inf = fits.open(\"input_file.fits\")\n",
    "fits_inf.info() \n",
    "fits_inf[0].header"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using ``fits.open`` allows us to look more generally at our data.  ``fits_inf[0].header`` gives us the same output as ``fits.getheader``.  What will you learn if you type ``fits_inf[1].header``?  Based on ``fits_inf.info()`` can you guess what will happen if you type ``fits_inf[2].header``?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's change the header to give it the correct object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "header['OBJECT'] = \"M31\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we have to write out the FITS file. Again, the convenience \n",
    "function for this is the most useful command to remember:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fits.writeto('output_file.fits', data, header, overwrite=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's it; you're done!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Two common and more complicated cases are worth mentioning (but if your needs \n",
    "are much more complex, you should consult the full documentation http://docs.astropy.org/en/stable/io/fits/). \n",
    "\n",
    "The first complication is that the FITS file you're examining and \n",
    "editing might have multiple HDU's (extensions), in which case you can \n",
    "specify the extension like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data1, header1 = fits.getdata(\"input_file.fits\", ext=1, header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This will get you the data and header associated with the `index=1` extension \n",
    "in the FITS file. Without specifying a number, `getdata()` will get the \n",
    "0th extension (equivalent to saying `ext=0`)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another useful tip is if you want to overwrite an existing FITS \n",
    "file. By default, `writeto()` won't let you do this, so you need to \n",
    "explicitly give it permission using the `clobber` keyword argument:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fits.writeto('output_file.fits', data, header, overwrite=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A final example is if you want to make a small change to a FITS file, like updating a header keyword, but you don't want to read in and write out the whole file, which can take a while.  Instead you can use the `mode='update'` read mode to do this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with fits.open('input_file.fits', mode='update') as filehandle:\n",
    "    filehandle[0].header['MYHDRKW'] = \"My Header Keyword\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read in the file you just wrote and add three header keywords:\n",
    "\n",
    "1. 'RA' for the Right Ascension of M31\n",
    "2. 'DEC' for the Declination of M31\n",
    "3. 'RADECSRC' with text indicating where you found the RA/Dec (web URL, textbook name, your photographic memory, etc.)\n",
    "\n",
    "Then write the updated header back out to a new file: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "astropy-tutorials": {
   "author": "Adrian M. Price-Whelan <adrn@astro.columbia.edu>",
   "date": "July 2013",
   "description": "Demonstrates how to read in, edit a FITS header, and then write it back out to disk using astropy.io.fits.",
   "link_name": "Editing a FITS header",
   "name": "",
   "published": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
